#include "chapter18.h"

int exercise18_1()
{
    return 0;
}

int exercise18_2()
{
    return 0;
}

int exercise18_3()
{
    int *p = nullptr;
    try
    {
        std::vector<int> v{1, 2, 3};
        std::ifstream in("ints");
        p = new int[v.size()];

        throw std::runtime_error("error");
    }
    catch (std::exception e)
    {
        cerr << e.what();
        delete[] p;
    }
    delete[] p;

    return 0;
}

int exercise18_4()
{
    try
    {
        // use of the C++ standard library
    }
    catch (std::overflow_error eobj)
    {
        // ...
    }
    catch (const std::runtime_error &re)
    {
        // ...
    }
    catch (std::exception)
    { /* ... */
    }

    return 0;
}

int exercise18_5()
{
    try
    {
        throw std::runtime_error("nothing happens");
    }
    catch (const std::exception &e)
    {
        cout << e.what() << endl;
        abort();
    }
    return 0;
}

int exercise18_6()
{
    typedef int EXCPTYPE;
    try
    {
        EXCPTYPE test(42);
        throw test;
    }
    catch (EXCPTYPE e)
    {
        cout << e << endl;
    }

    try
    {
        EXCPTYPE test(45);
        throw test;
    }
    catch (...)
    {
        cout << "got sth." << endl;
    }

    return 0;
}

int exercise18_7()
{
    return 0;
}

int exercise18_8()
{
    return 0;
}

int exercise18_9()
{
    return 0;
}

int exercise18_10()
{
    return 0;
}

int exercise18_11()
{
    return 0;
}

int exercise18_12()
{
    return 0;
}

int exercise18_13()
{
    return 0;
}

std::ostream &mathLib::MatrixLib::operator<<(std::ostream &out, const mathLib::MatrixLib::matrix &m)
{
    out << m.i << "," << m.j << "\n";
    return out;
}

mathLib::MatrixLib::matrix mathLib::MatrixLib::operator*(const mathLib::MatrixLib::matrix &m1, const mathLib::MatrixLib::matrix &m2)
{
    std::cout << m1 << m2;
    mathLib::MatrixLib::matrix m3(m1.i * m2.i, m1.j * m2.j);
    std::cout << m3;
    return m3;
}

int exercise18_14()
{
    using namespace mathLib::MatrixLib;
    matrix m1(2, 3), m2;
    cout << m1;
    m1 *m2;
    return 0;
}

int exercise18_15()
{
    return 0;
}

// using namespace Exercise;
// void manip()
// {
//     double dvartian = 3.1416;
//     int iobjtian = limittian + 1;
//     ++ivartian;
//     ++::ivartian;
// }

// void manip1()
// {
//     using namespace Exercise;
//     double dvartian = 3.1416;
//     int iobjtian = limittian + 1;
//     ++ivartian;
//     ++::ivartian;
// }

int exercise18_16()
{
    // when run with using namespace Exercise outside manip active.

    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.cpp:163:7: error: reference to ‘ivartian’ is ambiguous
    // [build]      ++ivartian;
    // [build]        ^
    // [build] In file included from /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.cpp:1:0:
    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.h:183:5: note: candidates are: int ivartian
    // [build]  int ivartian = 0;
    // [build]      ^
    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.h:179:9: note:                 int Exercise::ivartian
    // [build]      int ivartian = 0;
    // [build]          ^

    // manip();
    return 0;
}

int exercise18_17()
{
    // when run with using namespace test1::Exercise inside manip1 active.

    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.cpp: In function ‘void manip1()’:
    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.cpp:172:7: error: reference to ‘ivartian’ is ambiguous
    // [build]      ++ivartian;
    // [build]        ^
    // [build] In file included from /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.cpp:1:0:
    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.h:183:5: note: candidates are: int ivartian
    // [build]  int ivartian = 0;
    // [build]      ^
    // [build] /home/tian/projects/hellocpp/src/CppPrimer5th/chapter18/chapter18.h:179:9: note:                 int Exercise::ivartian
    // [build]      int ivartian = 0;
    // [build]          ^

    // manip1();
    return 0;
}

int exercise18_18()
{

    //     aaha
    // str
    // normal version swap.
    // 5
    // 4
    std::string a("str"), b("aaha");
    swap(a, b);

    cout << a << "\n"
         << b << "\n";

    int c(5), d(4);
    swap(c, d);

    cout << c << "\n"
         << d;

    return 0;
}

int exercise18_19()
{
    int c(5), d(4);
    std::swap(c, d);

    cout << c << "\n"
         << d;
    return 0;
}

int exercise18_20()
{
    // calling compute(int)
    // f();
    // calling compute(const void *)
    f1();
    return 0;
}

int exercise18_21()
{
    return 0;
}

int exercise18_22()
{
    // 1
    // 2
    // 3
    // 4
    // 5
    // 6
    // 7
    MI mi;
    return 0;
}

int exercise18_23()
{
    D *pd = new D;
    cout << "---------After init----------\n";
    cout << (*pd).get() << "\n";
    // allowed
    X *px = pd;
    cout << (*px).get() << "\n";
    // allowed
    A *pa = pd;
    cout << (*pa).get() << "\n";
    // allowed
    B *pb = pd;
    cout << (*pb).get() << "\n";
    // allowed
    C *pc = pd;
    cout << (*pc).get() << "\n";

    delete pd;

    return 0;
}

int exercise18_24()
{
    Bear *pb = new Panda("ying_ynag");
    pb->print();
    // pb->cubble();// zooanimal and bear does not have cubble func.
    // pb->highlight();// zooanimal and bear does not have highlight func.
    delete pb;

    ZooAnimal *pza = new Panda("ying_ynag");
    pza->print();
    // pza->cubble();   // zooanimal and bear does not have cubble func.
    // pza->highlight(); // zooanimal and bear does not have highlight func.
    delete pza;

    return 0;
}

int exercise18_25()
{
    Base1 *pb1 = new MI2;
    Base2 *pb2 = new MI2;
    D1 *pd1 = new MI2;
    D2 *pd2 = new MI2;

    pb1->print();
    pd1->print();
    pd2->print();

    cout << "---------Before delete----------delete pd1; \n";
    delete pd1;
    cout << "---------Before delete----------delete pd2; \n";
    delete pd2;
    cout << "---------Before delete----------delete pb1; \n";
    delete pb1;
    cout << "---------Before delete----------delete pb2; \n";
    delete pb2;
    return 0;
}

int exercise18_26()
{
    MI3 mi;
    // this is error becase MI3 has it's own print func,
    // and its print func will make other print funcs unseen.
    // mi.print(42);

    static_cast<AnotherBase1>(mi).print(42);

    return 0;
}

int exercise18_27()
{
    MI3 mi;
    mi.foo(1.4);

    return 0;
}

int exercise18_28()
{
    VMI vmi;
    static_cast<ThisDerived1>(vmi).foo('f');
    static_cast<ThisDerived2>(vmi).foo(200);

    vmi.bar('n');
    return 0;
}

int exercise18_29()
{
    // FinalClass ctr
    // FinalBase ctr
    // FinalD1 ctr
    // FinalD2 ctr
    // FinalMI ctr
    // FinalClass ctr
    // FinalFinal ctr
    // FinalFinal dctr
    // FinalClass dctr
    // FinalMI dctr
    // FinalD2 dctr
    // FinalD1 dctr
    // FinalBase dctr
    // FinalClass dctr

    // ff has 1 FinalBase part and 2 FinalClass parts.
    // Warning: direct base ‘FinalClass’ inaccessible in ‘FinalFinal’ due to ambiguity [enabled by default]
    FinalFinal ff;

    FinalBase *pb;
    FinalClass *pc;
    FinalMI *pmi;
    FinalD2 *pd2;
    // 虚继承
    // a value of type "FinalClass *" cannot be assigned to an entity of type "FinalBase *"
    // pb = new FinalClass; 

    // base class "FinalClass" is ambiguous
    // pc = new FinalFinal;

    // a value of type "FinalBase *" cannot be assigned to an entity of type "FinalMI *"
    // pmi = pb;
    pd2 = pmi;

    delete pb;
    delete pc;

    return 0;
}

int exercise18_30()
{
    // 由最底层的派生类来初始化虚基类，所以是以FinalMI来重置FinalBase的。
    FinalMI fm(1000,999,998);
    cout << fm.get();
    return 0;
}
